/**
 * TetisDB
 *
 * Implementação padrão de TetisDomain
 */
package br.com.tetisdb.domain;

import br.com.tetisdb.lang.TetisObject;
import br.com.tetisdb.util.TetisUtil;
import java.io.File;
import java.io.IOException;

import br.com.tetisdb.configure.TConfigureDomain;
import br.com.tetisdb.configure.TetisConfigureDomain;
import br.com.tetisdb.domain.session.TSession;
import br.com.tetisdb.domain.session.TetisSession;
import br.com.tetisdb.io.IOManager;
import br.com.tetisdb.io.domainConfig.ConfigIOManager;
import br.com.tetisdb.io.snapShot.SnapShotManager;
import br.com.tetisdb.lang.TetisHashMap;
import java.util.ArrayList;
import java.util.List;

public class TDomain extends TetisObject implements TetisDomain {
    /*
     * configuracao do TetisDomain
     */
    private TetisConfigureDomain configure;
    
    /*
     * Sessoes
     */
    private TetisHashMap<String, Object> sessions = new TetisHashMap<String, Object>();
    
    /*
     * Controlador de SnapShots
     */
    private SnapShotManager snapShotManager;
    
    //workspace
    private String workspace;
    
    /**
     * Construtor padrao.
     * @param nameDomain Nome do TetisDomain a ser criado.
     * @param workspace Path do workspace do TetisContainer desse dominio
     */
    public TDomain(String nameDomain, String workspace) throws IOException {
        super();
        tetisLogger.info("Criando TetisDomain: "+nameDomain);
        
        this.workspace = workspace;
        
        criaPath(nameDomain);
        resgataConfiguracao(nameDomain);
        
        // para criar caso tenha alguma alteracao no properties de configuracao
        if (!getConfigure().getNameDomain().equals(nameDomain)) {
            resgataConfiguracao(getConfigure().getNameDomain());
            criaPath(getConfigure().getNameDomain());
        }
        
        try {
            this.snapShotManager = new SnapShotManager(this);
        } catch (Exception e) {
            tetisLogger.error("Erro ao criar controlador de SnapShots. Erro: "+e.getMessage(), e);
        }
        
        //grava a configuracao atual no properties
        ConfigIOManager.writeConfigure(this);
    }
    
    /*
     * Le as configuracoes do TetisDomain
     *
     * @param nameDomain Nome do Dominio
     */
    private void resgataConfiguracao(String nameDomain) {
        tetisLogger.info("Lendo configuracoes do TetisDomain: "+nameDomain);
        
        configure = new TConfigureDomain(nameDomain);
        TetisConfigureDomain configTemp = ConfigIOManager.getConfigureDomain(this);
        
        if (configTemp != null) {
            configure = configTemp;
        }
    }
    
    /*
     * Criar os paths do TetisDomain
     *
     * @param nameDomain Nome do Dominio
     */
    private void criaPath(String nameDomain) throws IOException {
        tetisLogger.info("Criando paths do TetisDomain: "+nameDomain);
        
        if(!TetisUtil.stringIsValid(nameDomain))
            throw new IOException("NameDomain: "+nameDomain+" invalido!");
        
        String path = workspace + File.separator+ nameDomain;
        IOManager.createPath(path);
        IOManager.createPath(path + File.separator + PATH_DATA);
        IOManager.createPath(path + File.separator + PATH_BACKUP);
        IOManager.createPath(path + File.separator + PATH_CONFIG);
    }
    
    /**
     * Resgata o Nome do Domain
     *
     * @return Retorna o Nome do Dominio.
     */
    public String getNameDomain() {
        return getConfigure().getNameDomain();
    }
    
    /**
     * Cria uma Sessao ou resgata nesse TetisDomain
     *
     * @param user Nome do Usuario
     * @param password Senha
     * @return TetisSession as sessoes desse TetisDomain
     */
    public TetisSession getSession(String user, String password) {
        if (!existSession(user)) {
            TetisSession session = new TSession(snapShotManager, user);
            getSessions().put(user, session);
            
            return session;
        } else {
            return (TetisSession) getSessions().get(user);
        }
    }
    
    /**
     * Fecha uma TetisSession
     *
     * @param user Nome do Usuario.
     */
    public boolean closeSession(String user) {
        try {
            getSessions().remove(user);
            return true;
        } catch(Exception e) {
            return false;
        }
    }
    
    private boolean existSession(String user) {
        if (getSessions() != null) {
            return getSessions().exist(user);
        } else {
            this.sessions = new TetisHashMap<String, Object>();
            return false;
        }
    }
    
    /**
     * Resgata as TetisSessions de um TetisDomain
     *
     * @return Retorna TetisHashMap<String, Object>
     */
    public TetisHashMap<String, Object> getSessions() {
        return sessions;
    }
    
    /**
     * Resgata SnapShot
     *
     * @return Retorna SnapShotManager
     */
    public synchronized SnapShotManager getSnapShotManager() {
        return snapShotManager;
    }
    
    /**
     * Resgata a configuracao desse TetisDomain
     *
     * @return Retorna TetisConfigureDomain
     */
    public TetisConfigureDomain getConfigure() {
        return configure;
    }
    
    /**
     * Fecha o TetisDomain
     */
    public void close() {
        tetisLogger.info("Fechando o TetisDomain: "+getNameDomain());
        tetisLogger.debug("Fechando o TetisDomain: "+this);
        
        getSnapShotManager().pararThread();
        
        try {
            getSnapShotManager().takeSnapShot(); // dobrado por garantia
        } catch (Exception e) {
            tetisLogger.error("Erro ao gerar SnapShot. Erro: "+e.getMessage(), e);
        }
        
        tetisLogger.info("Fechando sessoes");
        List<TetisSession> sessions = new ArrayList(getSessions().values());
        
        for (TetisSession session : sessions ) {
            if(session != null) {
                session.close();
            }
        }
        
        tetisLogger.info("TetisDomain: "+getNameDomain()+" fechado.");
    }
    
    /**
     * Resgata o path completo de dados.
     *
     * @return String Caminho completo de dados.
     */
    public String getCompleteDataPath() {
        return workspace + File.separator + getConfigure().getNameDomain() + File.separator
                + TetisDomain.PATH_DATA + File.separator;
    }
    
    /**
     * Resgata o path completo de configuracoes.
     *
     * @return String Caminho completo de configuracoes.
     */
    public String getCompleteConfigPath() {
        return workspace + File.separator + getConfigure().getNameDomain() + File.separator
                + TetisDomain.PATH_CONFIG + File.separator;
    }
    
    /**
     * Resgata o path completo de backup de dados.
     *
     * @return String Caminho completo de backup de dados.
     */
    public String getCompleteBackupPath() {
        return workspace + File.separator + getConfigure().getNameDomain() + File.separator
                + TetisDomain.PATH_BACKUP + File.separator;
    }
    
    /**
     * Resgata o tempo do snapshot.
     *
     * @return int Tempo em milisegundos do SnapShot.
     */
    public int getTimeSnapShot() {
        return getConfigure().getTimeSnapShot();
    }
    
    /**
     * Apaga os paths do TetisDomain
     */
    public void destroyDomainPath() {
        try {
            IOManager.destroyPath(getCompleteBackupPath());
            IOManager.destroyPath(getCompleteConfigPath());
            IOManager.destroyPath(getCompleteDataPath());
        } catch (Exception e) {
            tetisLogger.error("Erro ao apagar path do TetisDomain: "+getNameDomain());
        }
    }
}
